/**
 * 滚动加载 Hook
 * 基于 IntersectionObserver API 实现滚动到顶部加载更多数据
 */

import { nextTick, onUnmounted, ref, type Ref } from 'vue';

// 滚动加载配置选项
export interface ScrollLoadOptions {
  // 根容器元素
  root?: HTMLElement | null;
  // 触发加载的距离（距离顶部多少像素开始加载）
  rootMargin?: string;
  // 触发阈值
  threshold?: number;
  // 是否启用
  enabled?: boolean;
}

// 滚动加载状态
export interface ScrollLoadState {
  isLoading: boolean;
  hasMore: boolean;
  error?: Error | null;
}

/**
 * 滚动加载 Hook
 * @param loadFn 加载数据的函数
 * @param options 配置选项
 */
export function useScrollLoad(loadFn: () => Promise<boolean>, options: ScrollLoadOptions = {}) {
  // 默认配置
  const defaultOptions: Required<ScrollLoadOptions> = {
    root: null,
    rootMargin: '20px 0px 0px 0px',
    threshold: 0.1,
    enabled: true,
  };

  const config = { ...defaultOptions, ...options };

  // 状态
  const isLoading = ref(false);
  const hasMore = ref(true);
  const error = ref<Error | null>(null);

  // 触发元素引用
  const triggerRef = ref<HTMLElement>();

  // IntersectionObserver 实例
  let observer: IntersectionObserver | null = null;

  /**
   * 执行加载数据
   */
  const executeLoad = async () => {
    if (isLoading.value || !hasMore.value || !config.enabled) {
      return;
    }

    try {
      isLoading.value = true;
      error.value = null;

      console.log('开始加载更多数据...');
      const success = await loadFn();

      if (success) {
        console.log('加载数据成功');
      } else {
        console.log('没有更多数据');
        hasMore.value = false;
      }
    } catch (err) {
      console.error('加载数据失败:', err);
      error.value = err as Error;
    } finally {
      isLoading.value = false;
    }
  };

  /**
   * 设置 IntersectionObserver
   */
  const setupObserver = () => {
    if (!triggerRef.value || !config.enabled) return;

    // 清理之前的观察器
    cleanup();

    observer = new IntersectionObserver(
      entries => {
        const entry = entries[0];
        if (entry.isIntersecting) {
          console.log('触发滚动加载');
          executeLoad();
        }
      },
      {
        root: config.root,
        rootMargin: config.rootMargin,
        threshold: config.threshold,
      }
    );

    observer.observe(triggerRef.value);
    console.log('IntersectionObserver 已设置');
  };

  /**
   * 清理观察器
   */
  const cleanup = () => {
    if (observer) {
      observer.disconnect();
      observer = null;
      console.log('IntersectionObserver 已清理');
    }
  };

  /**
   * 重置状态
   */
  const reset = () => {
    isLoading.value = false;
    hasMore.value = true;
    error.value = null;
  };

  /**
   * 手动触发加载
   */
  const manualLoad = () => {
    executeLoad();
  };

  /**
   * 设置是否还有更多数据
   */
  const setHasMore = (value: boolean) => {
    hasMore.value = value;
  };

  /**
   * 更新配置并重新设置观察器
   */
  const updateConfig = (newOptions: Partial<ScrollLoadOptions>) => {
    Object.assign(config, newOptions);
    if (triggerRef.value) {
      setupObserver();
    }
  };

  // 组件卸载时自动清理
  onUnmounted(() => {
    cleanup();
  });

  return {
    // 状态
    isLoading,
    hasMore,
    error,

    // 引用
    triggerRef,

    // 方法
    setupObserver,
    cleanup,
    reset,
    manualLoad,
    setHasMore,
    updateConfig,

    // 状态对象（方便传递）
    state: {
      isLoading,
      hasMore,
      error,
    } as {
      isLoading: Ref<boolean>;
      hasMore: Ref<boolean>;
      error: Ref<Error | null>;
    },
  };
}

/**
 * 滚动位置保持工具
 */
export function useScrollPosition(containerRef: Ref<HTMLElement | undefined>) {
  /**
   * 保持滚动位置（用于顶部加载新内容时）
   */
  const maintainScrollPosition = async (callback: () => Promise<void>) => {
    const container = containerRef.value;
    if (!container) return;

    // 记录当前滚动位置
    const oldScrollHeight = container.scrollHeight;
    const oldScrollTop = container.scrollTop;

    // 执行回调（通常是添加新内容）
    await callback();

    // 等待 DOM 更新
    await nextTick();

    // 恢复滚动位置
    if (container) {
      const newScrollHeight = container.scrollHeight;
      const heightDiff = newScrollHeight - oldScrollHeight;
      container.scrollTop = oldScrollTop + heightDiff;
    }
  };

  /**
   * 滚动到底部
   */
  const scrollToBottom = async () => {
    await nextTick();
    if (containerRef.value) {
      containerRef.value.scrollTop = containerRef.value.scrollHeight;
    }
  };

  /**
   * 滚动到顶部
   */
  const scrollToTop = async () => {
    await nextTick();
    if (containerRef.value) {
      containerRef.value.scrollTop = 0;
    }
  };

  /**
   * 平滑滚动到指定位置
   */
  const smoothScrollTo = (position: number) => {
    if (containerRef.value) {
      containerRef.value.scrollTo({
        top: position,
        behavior: 'smooth',
      });
    }
  };

  return {
    maintainScrollPosition,
    scrollToBottom,
    scrollToTop,
    smoothScrollTo,
  };
}

export default useScrollLoad;
